#!/usr/bin/perl

######################################################################
package Swignition::uF::species;
######################################################################

use Swignition::GenericParser::Utils;
use Swignition::uF;
use XML::LibXML qw(:all);
use strict;


sub consume
{
	my $page = shift;
	
	$page->{uF}->{species} = [ parse_all($page) ];
	foreach my $species (@{ $page->{uF}->{species} })
		{ $page->mergeSubject( $species->rdf_subject ); }
	if (defined $page->{uF}->{species}->[0])
		{ $page->mergeNS( $page->{uF}->{species}->[0] ); }
}

sub parse_all
{
	my $page   = shift;
	my $within = shift || $page->{DOM};
	my @nodes  = searchClass('biota', $within);
	my @rv;
	
	foreach my $adr (@nodes)
	{
		my $adr_parsed = parse($page, $adr);
		push @rv, $adr_parsed;
	}
	
	return @rv;
} #/sub parse_all


sub uri
{
	my $this = shift;
	my $all  = shift;
	my @rv;
	
	if (length $this->{_id})
	{
		push @rv, Swignition::uF::TDBURI($this->{_page}->uri.'#'.$this->{_id});
	}
	if (lc($this->{_dom}->tagName) eq 'body')
	{
		push @rv, Swignition::uF::TDBURI($this->{_page}->uri);
	}
	push @rv, Swignition::GenericParser::Utils::BNodeURI($this->{_dom}, 'Taxonomy')
		unless @rv;
	
	return $rv[0] unless (defined $all);
	while ($all) { shift @rv; $all--; }
	return @rv;
}


sub metadata_ns
{
	my $this = shift;
	return {
		'taxonomy' => {
			nsurl=>'http://purl.org/NET/biol/ns#',
			title=>'Biological Taxonomy Vocabulary 0.1 (Core)' 
		},
		'botany' => {
			nsurl=>'http://purl.org/NET/biol/botany#',
			title=>'Biological Taxonomy Vocabulary 0.1 (Botany)' 
		},
		'zoology' => {
			nsurl=>'http://purl.org/NET/biol/zoology#',
			title=>'Biological Taxonomy Vocabulary 0.1 (Zoology)' 
		},
		'taxonaux' => {
			nsurl=>'http://purl.org/NET/biol/auxiliary#',
			title=>'Biological Taxonomy Vocabulary 0.1 (Auxiliary)' 
		},
	};
} #/sub namespace


sub rdf_subject
{
	my $this    = shift;
	my $ranks   = $this->{_ranks};

	# Create RDF subject
	my $subject = Swignition::RDFModel::Subject->new($this->uri);
	$subject->addObject($this);
	$subject->setDom($this->{_dom});

	if ($this->{type} eq 'B')
	{
		$subject->addVal('http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
			Swignition::RDFModel::Value->new('http://purl.org/NET/biol/ns#BotTaxonomy', 1));
	}
	elsif ($this->{type} eq 'Z')
	{
		$subject->addVal('http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
			Swignition::RDFModel::Value->new('http://purl.org/NET/biol/ns#ZooTaxonomy', 1));
	}
	else
	{
		$subject->addVal('http://www.w3.org/1999/02/22-rdf-syntax-ns#type',
			Swignition::RDFModel::Value->new('http://purl.org/NET/biol/ns#Taxonomy', 1));
	}

	foreach my $term (keys %{ $ranks->{Terms} })
	{
		next unless (length $this->{$term});
		my $uri;
		
		if ($term eq 'division' && $this->{type} eq 'Z')
		{
			$uri = $ranks->{Prefixes}->{zoo}
				. $ranks->{Terms}->{$term}->{Camel};
		}
		elsif ($ranks->{Terms}->{$term}->{Type} =~ /C/)
		{
			$uri = $ranks->{Prefixes}->{core}
				. $ranks->{Terms}->{$term}->{Camel};
		}
		elsif ($this->{type} eq 'B'
		&& $ranks->{Terms}->{$term}->{Type} =~ /B/)
		{
			$uri = $ranks->{Prefixes}->{bot}
				. $ranks->{Terms}->{$term}->{Camel};
		}
		elsif ($this->{type} eq 'Z'
		&& $ranks->{Terms}->{$term}->{Type} =~ /Z/)
		{
			$uri = $ranks->{Prefixes}->{zoo}
				. $ranks->{Terms}->{$term}->{Camel};
		}
		else
		{
			$uri = $ranks->{Terms}->{$term}->{URI}->[0];
		}
		
		$subject->addVal($uri, Swignition::RDFModel::Value->new($this->{$term}));
	}
	
	foreach my $term (qw(binomial trinomial))
	{
		foreach my $sciname (@{ $this->{$term} })
		{
			$subject->addVal('http://purl.org/NET/biol/ns#name',
				Swignition::RDFModel::Value->new($sciname));
		}
	}

	foreach my $sciname (@{ $this->{'common-name'} })
	{
		$subject->addVal('http://purl.org/NET/biol/ns#commonName',
			Swignition::RDFModel::Value->new($sciname));
	}
	
	foreach my $sciname (@{ $this->{'authority'} })
	{
		$subject->addVal('http://purl.org/NET/biol/ns#authority',
			Swignition::RDFModel::Value->new($sciname));
	}
	
	return $subject;
	
} #/sub rdf_subject


sub parse
{
	my $page = shift;
	my $rv   = { '_dom'=>shift };
	my $pkg = __PACKAGE__;
	if (defined $page->{uF}->{_Shortcuts}->{$pkg}->{ $rv->{_dom}->getAttribute('_xpath') })
		{ return $page->{uF}->{_Shortcuts}->{$pkg}->{ $rv->{_dom}->getAttribute('_xpath') }; }
	else
		{ $page->{uF}->{_Shortcuts}->{$pkg}->{ $rv->{_dom}->getAttribute('_xpath') } = $rv; }
	
	my $root = $rv->{'_dom'}->cloneNode(1);

	my $id = $root->getAttribute('id');
	$rv->{_id} = $id if (length $id);
	$rv->{_page} = $page;
	
	my $implied_bot = 0;
	my $implied_zoo = 0;
	my $compact = 1;
	
	Swignition::uF::data_patterns($page, $root);
	Swignition::uF::destroyer($root);

	my $ranks = &ranks;
	$rv->{_ranks} = $ranks;
	
	foreach my $term (keys %{ $ranks->{Terms} })
	{
		my @nodes;
		push @nodes, searchClass($term, $root, 'taxo');
		push @nodes, searchClass('specific', $root, 'taxo')
			if ($term eq 'species');
		next unless ($nodes[0]);
		
		$compact = 0;
		$implied_bot = 1 if ($ranks->{Terms}->{$term}->{Type} eq 'B');
		$implied_zoo = 1 if ($ranks->{Terms}->{$term}->{Type} eq 'Z');
		
		$rv->{$term} = STRINGIFY($nodes[0], 'value');
	}
	
	foreach my $term (qw(binomial trinomial authority rank))
	{
		my @nodes;
		push @nodes, searchClass($term, $root, 'taxo');

		next unless ($nodes[0]);
		$compact = 0;
		foreach my $n (@nodes)
			{ push @{$rv->{$term}}, STRINGIFY($n, 'value'); }
	}

	foreach my $term (qw(vernacular common-name cname))
	{
		my @nodes;
		push @nodes, Swignition::GenericParser::Utils::searchClass($term, $root, 'taxo');
		next unless ($nodes[0]);

		$compact = 0;
		foreach my $n (@nodes)
			{ push @{$rv->{'common-name'}}, Swignition::GenericParser::Utils::STRINGIFY($n, 'value'); }
	}

	if ($compact)
	{
		$compact = Swignition::GenericParser::Utils::STRINGIFY($root, 'value');
		$compact =~ s/(^\s+|\s+$)//g;
		$compact =~ s/\s+/ /g;
		$rv->{binomial} = [ $compact ] if ($compact);
	}
	
	if ($root->getAttribute('class') =~ /\b(zoology)\b/)
		{ $rv->{type} = 'Z'; }
	elsif ($root->getAttribute('class') =~ /\b(botany)\b/)
		{ $rv->{type} = 'B'; }
	elsif ($implied_zoo && !$implied_bot)
		{ $rv->{type} = 'Z'; }
	elsif ($implied_bot && !$implied_zoo)
		{ $rv->{type} = 'B'; }
	
	bless $rv;
	return $rv;
	
} #/sub parse


sub ranks
{
	my $n3 = <<NTRIPLES

# OK - Swignition doesn't really parse all this N3 properly. It only really
# uses the prefixes, plus the property lists, and it's very sensitive to
# whitespace changes.

\@prefix	core:	<http://purl.org/NET/biol/ns#> .
\@prefix	bot:	<http://purl.org/NET/biol/botany#> .
\@prefix	zoo:	<http://purl.org/NET/biol/zoology#> .
\@prefix	owl:	<http://www.w3.org/2002/07/owl#> .

# Core
core:class	a owl:ObjectProperty .
core:division	a owl:ObjectProperty .
core:family	a owl:ObjectProperty .
core:genus	a owl:ObjectProperty .
core:kingdom	a owl:ObjectProperty .
core:order	a owl:ObjectProperty .
core:phylum	a owl:ObjectProperty .
core:rank	a owl:ObjectProperty .
core:species	a owl:ObjectProperty .

# Botany
bot:aberration	a owl:ObjectProperty .
bot:aggregate	a owl:ObjectProperty .
bot:biovar	a owl:ObjectProperty .
bot:branch	a owl:ObjectProperty .
bot:breed	a owl:ObjectProperty .
bot:class	a owl:ObjectProperty .
bot:claudius	a owl:ObjectProperty .
bot:cohort	a owl:ObjectProperty .
bot:complex	a owl:ObjectProperty .
bot:convariety	a owl:ObjectProperty .
bot:cultivar	a owl:ObjectProperty .
bot:cultivarGroup	a owl:ObjectProperty .
bot:division	a owl:ObjectProperty .
bot:domain	a owl:ObjectProperty .
bot:empire	a owl:ObjectProperty .
bot:falanx	a owl:ObjectProperty .
bot:family	a owl:ObjectProperty .
bot:familyGroup	a owl:ObjectProperty .
bot:form	a owl:ObjectProperty .
bot:genus	a owl:ObjectProperty .
bot:genusGroup	a owl:ObjectProperty .
bot:gigaorder	a owl:ObjectProperty .
bot:grade	a owl:ObjectProperty .
bot:grandorder	a owl:ObjectProperty .
bot:group	a owl:ObjectProperty .
bot:groupOfBreeds	a owl:ObjectProperty .
bot:hybrid	a owl:ObjectProperty .
bot:hyperorder	a owl:ObjectProperty .
bot:infraclass	a owl:ObjectProperty .
bot:infradomain	a owl:ObjectProperty .
bot:infrafamily	a owl:ObjectProperty .
bot:infraform	a owl:ObjectProperty .
bot:infragenus	a owl:ObjectProperty .
bot:infrakingdom	a owl:ObjectProperty .
bot:infralegion	a owl:ObjectProperty .
bot:infraorder	a owl:ObjectProperty .
bot:infraphylum	a owl:ObjectProperty .
bot:infrasection	a owl:ObjectProperty .
bot:infraseries	a owl:ObjectProperty .
bot:infraspecies	a owl:ObjectProperty .
bot:infratribe	a owl:ObjectProperty .
bot:infravariety	a owl:ObjectProperty .
bot:interkingdom	a owl:ObjectProperty .
bot:kingdom	a owl:ObjectProperty .
bot:klepton	a owl:ObjectProperty .
bot:legion	a owl:ObjectProperty .
bot:lusus	a owl:ObjectProperty .
bot:magnorder	a owl:ObjectProperty .
bot:megaorder	a owl:ObjectProperty .
bot:microspecies	a owl:ObjectProperty .
bot:midkingdom	a owl:ObjectProperty .
bot:midphylum	a owl:ObjectProperty .
bot:mirorder	a owl:ObjectProperty .
bot:nation	a owl:ObjectProperty .
bot:order	a owl:ObjectProperty .
bot:parvclass	a owl:ObjectProperty .
bot:parvorder	a owl:ObjectProperty .
bot:pathovar	a owl:ObjectProperty .
bot:phylum	a owl:ObjectProperty .
bot:population	a owl:ObjectProperty .
bot:section	a owl:ObjectProperty .
bot:sectionOfBreeds	a owl:ObjectProperty .
bot:series	a owl:ObjectProperty .
bot:serogroup	a owl:ObjectProperty .
bot:serovar	a owl:ObjectProperty .
bot:species	a owl:ObjectProperty .
bot:speciesGroup	a owl:ObjectProperty .
bot:speciesSubgroup	a owl:ObjectProperty .
bot:strain	a owl:ObjectProperty .
bot:subclass	a owl:ObjectProperty .
bot:subcohort	a owl:ObjectProperty .
bot:subdivision	a owl:ObjectProperty .
bot:subdomain	a owl:ObjectProperty .
bot:subfamily	a owl:ObjectProperty .
bot:subfamilyGroup	a owl:ObjectProperty .
bot:subform	a owl:ObjectProperty .
bot:subgenus	a owl:ObjectProperty .
bot:subgroup	a owl:ObjectProperty .
bot:subkingdom	a owl:ObjectProperty .
bot:sublegion	a owl:ObjectProperty .
bot:suborder	a owl:ObjectProperty .
bot:subphylum	a owl:ObjectProperty .
bot:subsection	a owl:ObjectProperty .
bot:subseries	a owl:ObjectProperty .
bot:subspecies	a owl:ObjectProperty .
bot:subtribe	a owl:ObjectProperty .
bot:subvariety	a owl:ObjectProperty .
bot:superclass	a owl:ObjectProperty .
bot:supercohort	a owl:ObjectProperty .
bot:superdomain	a owl:ObjectProperty .
bot:superfamily	a owl:ObjectProperty .
bot:superform	a owl:ObjectProperty .
bot:supergenus	a owl:ObjectProperty .
bot:superkingdom	a owl:ObjectProperty .
bot:superlegion	a owl:ObjectProperty .
bot:superorder	a owl:ObjectProperty .
bot:superphylum	a owl:ObjectProperty .
bot:supersection	a owl:ObjectProperty .
bot:superseries	a owl:ObjectProperty .
bot:superspecies	a owl:ObjectProperty .
bot:supertribe	a owl:ObjectProperty .
bot:supervariety	a owl:ObjectProperty .
bot:suprakingdom	a owl:ObjectProperty .
bot:supraphylum	a owl:ObjectProperty .
bot:synklepton	a owl:ObjectProperty .
bot:tribe	a owl:ObjectProperty .
bot:variety	a owl:ObjectProperty .

# Zoology
zoo:aberration	a owl:ObjectProperty .
zoo:aggregate	a owl:ObjectProperty .
zoo:biovar	a owl:ObjectProperty .
zoo:branch	a owl:ObjectProperty .
zoo:breed	a owl:ObjectProperty .
zoo:class	a owl:ObjectProperty .
zoo:claudius	a owl:ObjectProperty .
zoo:cohort	a owl:ObjectProperty .
zoo:complex	a owl:ObjectProperty .
zoo:convariety	a owl:ObjectProperty .
zoo:cultivar	a owl:ObjectProperty .
zoo:cultivarGroup	a owl:ObjectProperty .
zoo:division	a owl:ObjectProperty .
zoo:domain	a owl:ObjectProperty .
zoo:empire	a owl:ObjectProperty .
zoo:falanx	a owl:ObjectProperty .
zoo:family	a owl:ObjectProperty .
zoo:familyGroup	a owl:ObjectProperty .
zoo:form	a owl:ObjectProperty .
zoo:genus	a owl:ObjectProperty .
zoo:genusGroup	a owl:ObjectProperty .
zoo:gigaorder	a owl:ObjectProperty .
zoo:grade	a owl:ObjectProperty .
zoo:grandorder	a owl:ObjectProperty .
zoo:group	a owl:ObjectProperty .
zoo:groupOfBreeds	a owl:ObjectProperty .
zoo:hybrid	a owl:ObjectProperty .
zoo:hyperorder	a owl:ObjectProperty .
zoo:infraclass	a owl:ObjectProperty .
zoo:infradomain	a owl:ObjectProperty .
zoo:infrafamily	a owl:ObjectProperty .
zoo:infraform	a owl:ObjectProperty .
zoo:infragenus	a owl:ObjectProperty .
zoo:infrakingdom	a owl:ObjectProperty .
zoo:infralegion	a owl:ObjectProperty .
zoo:infraorder	a owl:ObjectProperty .
zoo:infraphylum	a owl:ObjectProperty .
zoo:infraspecies	a owl:ObjectProperty .
zoo:infratribe	a owl:ObjectProperty .
zoo:infravariety	a owl:ObjectProperty .
zoo:interkingdom	a owl:ObjectProperty .
zoo:kingdom	a owl:ObjectProperty .
zoo:klepton	a owl:ObjectProperty .
zoo:legion	a owl:ObjectProperty .
zoo:lusus	a owl:ObjectProperty .
zoo:magnorder	a owl:ObjectProperty .
zoo:megaorder	a owl:ObjectProperty .
zoo:microspecies	a owl:ObjectProperty .
zoo:midkingdom	a owl:ObjectProperty .
zoo:midphylum	a owl:ObjectProperty .
zoo:mirorder	a owl:ObjectProperty .
zoo:nation	a owl:ObjectProperty .
zoo:order	a owl:ObjectProperty .
zoo:parvclass	a owl:ObjectProperty .
zoo:parvorder	a owl:ObjectProperty .
zoo:pathovar	a owl:ObjectProperty .
zoo:phylum	a owl:ObjectProperty .
zoo:population	a owl:ObjectProperty .
zoo:section	a owl:ObjectProperty .
zoo:sectionOfBreeds	a owl:ObjectProperty .
zoo:series	a owl:ObjectProperty .
zoo:serogroup	a owl:ObjectProperty .
zoo:serovar	a owl:ObjectProperty .
zoo:species	a owl:ObjectProperty .
zoo:speciesGroup	a owl:ObjectProperty .
zoo:speciesSubgroup	a owl:ObjectProperty .
zoo:strain	a owl:ObjectProperty .
zoo:subclass	a owl:ObjectProperty .
zoo:subcohort	a owl:ObjectProperty .
zoo:subdivision	a owl:ObjectProperty .
zoo:subdomain	a owl:ObjectProperty .
zoo:subfamily	a owl:ObjectProperty .
zoo:subfamilyGroup	a owl:ObjectProperty .
zoo:subform	a owl:ObjectProperty .
zoo:subgenus	a owl:ObjectProperty .
zoo:subgroup	a owl:ObjectProperty .
zoo:subkingdom	a owl:ObjectProperty .
zoo:sublegion	a owl:ObjectProperty .
zoo:suborder	a owl:ObjectProperty .
zoo:subphylum	a owl:ObjectProperty .
zoo:subsection	a owl:ObjectProperty .
zoo:subseries	a owl:ObjectProperty .
zoo:subspecies	a owl:ObjectProperty .
zoo:subtribe	a owl:ObjectProperty .
zoo:subvariety	a owl:ObjectProperty .
zoo:superclass	a owl:ObjectProperty .
zoo:supercohort	a owl:ObjectProperty .
zoo:superdivision	a owl:ObjectProperty .
zoo:superdomain	a owl:ObjectProperty .
zoo:superfamily	a owl:ObjectProperty .
zoo:superform	a owl:ObjectProperty .
zoo:supergenus	a owl:ObjectProperty .
zoo:superkingdom	a owl:ObjectProperty .
zoo:superlegion	a owl:ObjectProperty .
zoo:superorder	a owl:ObjectProperty .
zoo:superphylum	a owl:ObjectProperty .
zoo:superspecies	a owl:ObjectProperty .
zoo:supertribe	a owl:ObjectProperty .
zoo:supervariety	a owl:ObjectProperty .
zoo:suprakingdom	a owl:ObjectProperty .
zoo:supraphylum	a owl:ObjectProperty .
zoo:synklepton	a owl:ObjectProperty .
zoo:tribe	a owl:ObjectProperty .
zoo:variety	a owl:ObjectProperty .

NTRIPLES
	;
	
	my $plain_n3 = '';
	foreach (split /\r?\n/, $n3)
	{
		next unless /[A-Za-z0-9]/;
		next if /^\s*\#/;
		$plain_n3 .= "$_\n";
	}
	
	my $data = {};
	foreach (split /\s+\.\s+/, $plain_n3)
	{
		s/(^\s+|\s+$)//g;
		s/\s+/ /g;
		my @word = split / /;
		
		if ($word[0] eq '@prefix')
		{
			my $code = $word[1];
			my $uri  = $word[2];
			$code =~ s/\:$//;
			$uri  =~ s/(^\<|\>$)//g;
			
			$data->{Prefixes}->{$code} = $uri;
		}
		
		elsif ($word[1] eq 'a' && $word[2] eq 'owl:ObjectProperty')
		{
			my ($code, $term) = split /\:/, $word[0];
			my $uri = $data->{Prefixes}->{$code} . $term;
			
			my $type = 'C';
			$type = 'B' if ($uri =~ /botany/);
			$type = 'Z' if ($uri =~ /zoology/);
			
			my $hyphen = $term;
			$hyphen =~ s/([A-Z])/'-'.lc($1)/eg;
			
			$data->{Terms}->{$hyphen}->{Type} .= $type;
			$data->{Terms}->{$hyphen}->{Camel} = $term;
			$data->{Terms}->{$hyphen}->{Hyphen} = $hyphen;
			push @{ $data->{Terms}->{$hyphen}->{URI} }, $uri;
		}
	}

#	foreach my $term (sort keys %{$data->{Terms}})
#	{
#		my $classes = '';
#		$classes .= "core " if ($data->{Terms}->{$term}->{Type} =~ /C/);
#		$classes .= "botany " if ($data->{Terms}->{$term}->{Type} =~ /B/);
#		$classes .= "zoology " if ($data->{Terms}->{$term}->{Type} =~ /Z/);
#		$classes .= "botany-only " if ($data->{Terms}->{$term}->{Type} =~ /^[CB]*$/);
#		$classes .= "zoology-only " if ($data->{Terms}->{$term}->{Type} =~ /^[CZ]*$/);
#		print "<li><code class=\"$classes\">$term</code></li>\n";
#	}
	
	return $data;

}

1; #/package Swignition::uF::species

